import org.junit.Test;

import java.math.BigDecimal;
import java.time.LocalDate;
import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.Stream;

public class LambdaTest {

    @Test//转换
    public void test1() {
        //将字符串转化为map
        /**
         * index.do?itemId=1&userId=1000&type=20&token=111111&key=index
         */
        String s = "index.do?itemId=1&userId=1000&type=20&token=111111&key=index";
        //转化为map，key为数组第0个，value为数组第一个，toMap有两个Function参数，以下代码代表输入一个数组输出一个数组中的值
        Map<String, String> map = Stream.of(s.split("&")).map(str -> str.split("=")).collect(Collectors.toMap(arr -> arr[0], arr -> arr[1]));
        System.out.println(map);//{type=20, userId=1000, index.do?itemId=1, key=index, token=111111}
    }

    private List<Book> bookTest() {
        List<Book> list = new ArrayList<>();
        //Integer id, String name, BigDecimal price, String type, LocalDate pulishDate
        list.add(new Book(1, "书1", 225.6d, "分类一", LocalDate.now().plusDays(10)));
        list.add(new Book(2, "书2", 225.6d, "分类一", LocalDate.now().plusDays(15)));
        list.add(new Book(3, "书3", 125.6d, "分类一", LocalDate.now().plusMonths(1)));
        list.add(new Book(4, "书4", 5.6d, "分类二", LocalDate.now().plusMonths(2)));
        list.add(new Book(5, "书5", 2.6d, "分类二", LocalDate.now().plusMonths(4)));
        list.add(new Book(6, "书6", 45.6d, "分类二", LocalDate.now().plusYears(1)));
        list.add(new Book(7, "书7", 55.6d, "分类三", LocalDate.now().minusYears(1)));
        list.add(new Book(8, "书8", 55.6d, "分类三", LocalDate.now().plusYears(2)));
        list.add(new Book(9, "书9", 25.16d, "分类四", LocalDate.now().minusYears(10)));
        list.add(new Book(10, "书10", 25.63d, "分类四", LocalDate.now().minusMonths(3)));
        return list;
    }

    @Test//重点掌握，很常见
    public void test2() {
        //取出所有book的ID放到List中
        List<Book> books = this.bookTest();
        List<Integer> list = books.stream().map(book -> book.getId()).collect(Collectors.toList());
        System.out.println(list);//[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

        List<Book> newBooks = books.stream().filter(b -> b.getPrice().compareTo(new BigDecimal(10)) > 0).map(book -> {book.setName("新书");return book;}).peek(System.out::println).collect(Collectors.toList());
        System.out.println(newBooks.toString());
        //使用方法的引用
        List<Integer> ids = books.stream().map(Book::getId).peek(System.out::println).collect(Collectors.toList());
        System.out.println(ids);//[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
        //取出ID以后其使用，分割，转化为一个字符串，先将其转成字符串，然后使用 , 拼接
        String s = books.stream().map(book -> book.getId().toString()).collect(Collectors.joining(","));
        System.out.println(s);//1,2,3,4,5,6,7,8,9,10
        String s1 = books.stream().map(book -> book.getId().toString()).collect(Collectors.joining(",", "(", ")"));//表示在最前面加一个括号在最后面加一个括号
        System.out.println(s1);//(1,2,3,4,5,6,7,8,9,10)

        String s2 = books.stream().map(book -> "'" + book.getId() + "'").collect(Collectors.joining(",", "(", ")"));
        System.out.println(s2);//('1','2','3','4','5','6','7','8','9','10') 每个字符使用单引号割开
    }

    @Test
    public void test3() {
        List<String> list = this.bookTest().stream().map(Book::getType).collect(Collectors.toList());
        System.out.println(list);//[分类一, 分类一, 分类一, 分类二, 分类二, 分类二, 分类三, 分类三, 分类四, 分类四]
        //去重
        List<String> list1 = this.bookTest().stream().map(Book::getType).distinct().collect(Collectors.toList());
        Set<String> set = this.bookTest().stream().map(Book::getType).collect(Collectors.toSet());
        System.out.println(list1);//[分类一, 分类二, 分类三, 分类四]
        System.out.println(set);//[分类二, 分类四, 分类三, 分类一]
    }

    @Test//排序
    public void test4() {
        //根据价格排序
        //从低到高，输出价格排序
        List<BigDecimal> list = this.bookTest().stream().map(Book::getPrice).sorted(Comparator.naturalOrder()).collect(Collectors.toList());
        //从高到低，输出价格排序
        List<BigDecimal> list1 = this.bookTest().stream().map(Book::getPrice).sorted(Comparator.reverseOrder()).collect(Collectors.toList());
        System.out.println("从低到高，输出价格排序:" + list);
        System.out.println("从高到低，输出价格排序:" + list1);
        //输出书本集合，从低到高排序
        List<Book> list2 = this.bookTest().stream().sorted((book1, book2) -> book2.getPrice().compareTo(book1.getPrice())).collect(Collectors.toList());
        System.out.println("输出书本集合，从低到高排序:" + list2);
        //输出书本集合，从高到低排序
        //转化为一个Comparator<Book>对象
        Comparator<Book> comparator = (book1, book2) -> book2.getPrice().compareTo(book1.getPrice());
        List<Book> books = this.bookTest().stream().sorted(comparator.reversed()).collect(Collectors.toList());
        System.out.println("输出书本集合，从高到低排序:" + books);
        System.out.println("--------------------------------------------");
        //按照价格排序从高到低，如果价格相同，按照出版时间排序从晚到早
        List<Book> list3 = this.bookTest().stream().sorted(comparator.reversed()).sorted(comparator.thenComparing((book1, book2) ->
                book2.getPulishDate().isAfter(book1.getPulishDate()) ? 1 : -1)).collect(Collectors.toList());
        System.out.println("按照价格排序从高到低，如果价格相同，按照出版时间排序从晚到早" + list3);
        //可以实现多个排序，类似数据库效果
        System.out.println("--------------------------------------------");
        //使用更简单的方式
        //默认排序，从低到高
        List<Book> list4 = this.bookTest().stream().sorted(Comparator.comparing(Book::getPrice)).collect(Collectors.toList());
        //从高到低
        List<Book> list5 = this.bookTest().stream().sorted(Comparator.comparing(Book::getPrice).reversed()).collect(Collectors.toList());
        //多个排序
        List<Book> list6 = this.bookTest().stream().sorted(Comparator.comparing(Book::getPrice).thenComparing(Book::getPulishDate).reversed()).collect(Collectors.toList());
        System.out.println(list6);
    }

    @Test
    public void test5() {
        //转化成一个map，key是ID，value是Book
//        Map<Integer,Book> map = this.bookTest().stream().collect(Collectors.toMap(book->book.getId(),book -> book));
        Map<Integer, Book> map1 = this.bookTest().stream().collect(Collectors.toMap(Book::getId, book -> book));
        System.out.println(map1);
    }

    @Test
    public void test6() {
        //计算平均价格
        Double avg = this.bookTest().stream().collect(Collectors.averagingDouble(book->book.getPrice().doubleValue()));
        System.out.println("计算平均价格:" + avg);
        //取出价格最高的一本书
        Book max = this.bookTest().stream().collect(Collectors.maxBy(Comparator.comparing(Book::getPrice))).get();
        System.out.println("取出价格最高的一本书:" + max);
        //取出价格最低的一本书
        Book min = this.bookTest().stream().collect(Collectors.minBy(Comparator.comparing(Book::getPrice))).get();
        System.out.println("取出价格最低的一本书" + min);
        //取出最早发布时间的书
        Book bookEarly = this.bookTest().stream().collect(Collectors.minBy(Comparator.comparing(Book::getPulishDate))).get();
        System.out.println("取出最早发布时间的书" + bookEarly);
        //找出最贵的,且是最新出版的
        Book book = this.bookTest().stream().collect(Collectors.maxBy(Comparator.comparing(Book::getPrice).thenComparing(Book::getPulishDate).reversed())).get();
        System.out.println("找出最贵的,且是最新出版的:" + book);
    }

    @Test
    public void test7() {
        //按类型分组
        //返回的是一个map，key对应的是类型，value对应的是每一种类型中的具体的书本
        Map<String, List<Book>> map = this.bookTest().stream().collect(Collectors.groupingBy(Book::getType));
        System.out.println("按类型分组" + map);
        map.keySet().forEach(key -> {
                    System.out.println(key);
                    System.out.println(map.get(key));
                }
        );
        //统计每本类型有多少本书,输出的是一个map<String,Long>,key是数组，Long是数量
        Map<String, Long> map1 = this.bookTest().stream().collect(Collectors.groupingBy(Book::getType, Collectors.counting()));
        System.out.println("统计每本类型有多少本书：" + map1);//{分类二=3, 分类四=2, 分类三=2, 分类一=3}
        //按照价格分类，求出每种类型的书籍的总价格
        Map<String, Double> map2 = this.bookTest().stream().collect(Collectors.groupingBy(Book::getType, Collectors.summingDouble(b -> b.getPrice().doubleValue())));
        System.out.println("按照价格分类，求出每种类型的书籍的总价格" + map2);
        //每种类型书籍的平均价格
        Map<String, Double> map3 = this.bookTest().stream().collect(Collectors.groupingBy(Book::getType, Collectors.averagingDouble(b -> b.getPrice().doubleValue())));
        System.out.println("每种类型书籍的平均价格:" + map3);
        //找出每种类型最贵的
        Map<String, Optional<Book>> map4 = this.bookTest().stream().collect(Collectors.groupingBy(Book::getType, Collectors.maxBy(Comparator.comparing(Book::getPrice))));
        System.out.println("找出每种类型最贵的" + map4);
        //找出每种类型最便宜的
        Map<String, Optional<Book>> map5 = this.bookTest().stream().collect(Collectors.groupingBy(Book::getType, Collectors.minBy(Comparator.comparing(Book::getPrice))));
        System.out.println(map5);
        System.out.println("----------------------------------------------------");
        Book maxBook = this.bookTest().stream().max(Comparator.comparing(Book::getPrice)).get();
        List<Book> maxBooks = this.bookTest().stream().filter(b -> b.getPrice().compareTo(maxBook.getPrice()) == 0).collect(Collectors.toList());
        System.out.println("最贵的书有多本，取出最贵的多本书籍的集合"+maxBooks);
        System.out.println("----------------------------------------------------");
        //每种类型出版时间最晚的
        Map<String, Optional<Book>> map6 = this.bookTest().stream().collect(Collectors.groupingBy(Book::getType, Collectors.maxBy(Comparator.comparing(Book::getPulishDate))));
    }

    @Test
    public void test8() {
        //过滤
        //取出80块以上的书，时间从近到远
        this.bookTest().stream().filter(book -> book.getPrice().doubleValue() >= 80).sorted(Comparator.comparing(Book::getPulishDate).reversed()).forEach(System.out::println);
        List<Book> list = this.bookTest().stream().filter(book -> book.getPrice().doubleValue() >= 80).sorted(Comparator.comparing(Book::getPulishDate).reversed()).collect(Collectors.toList());
        System.out.println("取出80块以上的书，时间从近到远" + list);
    }

    @Test
    public void listTest(){
        List<String> l1 = new ArrayList<>();
        l1.add("1");
        l1.add("2");
        l1.add("3");
        List<String> l2 = new ArrayList<>();
        l2.add("1");
        l2.add("2");
        l2.add("4");
        List<String> l3 = new ArrayList<>();
        l3.addAll(l1);
        l3.addAll(l2);
        System.out.println(l3.toString());
    }
}
